/*
@(#)LoginSecurityHandler   2023-04-19
 
Copyright (c) 2011-2023 杭州湖畔网络技术有限公司 
保留所有权利 
本软件为杭州湖畔网络技术有限公司所有及包含机密信息，须遵守其相关许可证条款进行使用。
Copyright (c) 2011-2023 HUPUN Network Technology CO.,LTD.
All rights reserved.
This software is the confidential and proprietary information of HUPUN
Network Technology CO.,LTD("Confidential Information").  You shall not
disclose such Confidential Information and shall use it only in
accordance with the terms of the license agreement you entered into with HUPUN.
Website：http://www.hupun.com
*/
package org.obp.auth.redis;

import cn.hutool.core.date.LocalDateTimeUtil;
import org.obp.auth.utils.MobileUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Component;

import java.time.Duration;
import java.time.LocalDateTime;
import java.util.concurrent.TimeUnit;

/**
 * @author: Jackey 2023/4/19
 */
@Component
public class RedisLoginHelper {

    public static final int SMS_ALIVE = 300;
    public static final int SMS_INTERVAL = 59;
    public static final int SMS_DAILY_MAX = 5;

    public static final int EMAIL_ALIVE = 300;
    public static final int EMAIL_INTERVAL = 59;

    public static final int CODE_ERROR_MAX = 3;
    public static final int WALLET_PASSWD_ERROR_MAX = 10;
    public static final int WALLET_PASSWD_ERROR_WARN = 7;

    public static final String SMS_CODE_KEY = "SMS:CODE:";
    public static final String SMS_INTERVAL_KEY = "SMS:INTERVAL:";
    public static final String SMS_DAILY_COUNT_KEY = "SMS:DAILY:COUNT:";
    public static final String SMS_CREDENTIAL_KEY = "SMS:CREDENTIAL:";

    public static final String EMAIL_CODE_KEY = "EMAIL:CODE:";
    public static final String EMAIL_INTERVAL_KEY = "EMAIL:INTERVAL:";
    public static final String EMAIL_CREDENTIAL_KEY = "EMAIL:CREDENTIAL:";

    public static final String SMS_CODE_ERROR_COUNT_KEY = "SMS:CODE:ERROR:COUNT:";
    public static final String EMAIL_CODE_ERROR_COUNT_KEY = "EMAIL:CODE:ERROR:COUNT:";
    public static final String WALLET_PASSWD_ERROR_COUNT_KEY = "WALLET:PASSWORD:ERROR:COUNT:";

    @Autowired
    private StringRedisTemplate redisTemplate;

    public boolean checkSmsInterval(String nation, String mobile) {
        String key = SMS_INTERVAL_KEY + mobileKey(nation, mobile);
        Object result = redisTemplate.opsForValue().get(key);
        return result == null;
    }

    public boolean checkSmsDailyCount(String nation, String mobile) {
        String key = SMS_DAILY_COUNT_KEY + mobileKey(nation, mobile);
        Object count = redisTemplate.opsForValue().get(key);
        if (count == null) return true;
        else {
            int num = Integer.parseInt(String.valueOf(count));
            return num < SMS_DAILY_MAX;
        }
    }

    public boolean checkSmsCodeErrorCount(String nation, String mobile, String type) {
        String key = SMS_CODE_ERROR_COUNT_KEY + mobileKey(nation, mobile) + ":" + type + ":";
        Object count = redisTemplate.opsForValue().get(key);
        if (count == null) return true;
        else {
            int num = Integer.parseInt(String.valueOf(count));
            return num < CODE_ERROR_MAX;
        }
    }

    public void createSmsCode(String nation, String mobile, String type, String code) {
        String key = SMS_CODE_KEY + mobileKey(nation, mobile) + ":" + type + ":";
        redisTemplate.opsForValue().set(key, code, SMS_ALIVE, TimeUnit.SECONDS);
    }

    public void sendSmsInterval(String nation, String mobile) {
        String key = SMS_INTERVAL_KEY + mobileKey(nation, mobile);
        redisTemplate.opsForValue().set(key, "1", SMS_INTERVAL, TimeUnit.SECONDS);
    }

    public void delSmsInterval(String nation, String mobile) {
        String key = SMS_INTERVAL_KEY + mobileKey(nation, mobile);
        redisTemplate.delete(key);
    }

    public void sendSmsDailyCount(String nation, String mobile) {
        String key = SMS_DAILY_COUNT_KEY + mobileKey(nation, mobile);
        Object count = redisTemplate.opsForValue().get(key);
        LocalDateTime now = LocalDateTime.now();
        LocalDateTime endOfDay = LocalDateTimeUtil.endOfDay(now);
        Duration between = LocalDateTimeUtil.between(now, endOfDay);
        if (count == null) {
            redisTemplate.opsForValue().set(key, "1", between.getSeconds(), TimeUnit.SECONDS);
        } else {
            int num = Integer.parseInt(String.valueOf(count)) + 1;
            redisTemplate.opsForValue().set(key, String.valueOf(num), between.getSeconds(), TimeUnit.SECONDS);
        }
    }

    public String getSmsCode(String nation, String mobile, String type) {
        String key = SMS_CODE_KEY + mobileKey(nation, mobile) + ":" + type + ":";
        Object code = redisTemplate.opsForValue().get(key);
        if (code == null) return null;
        else return String.valueOf(code);
    }

    public void incrSmsCodeErrorCount(String nation, String mobile, String type) {
        String key0 = SMS_CODE_KEY + mobileKey(nation, mobile) + ":" + type + ":";
        Long expire = redisTemplate.getExpire(key0);
        if (expire == null || expire < 0) return;

        String key = SMS_CODE_ERROR_COUNT_KEY + mobileKey(nation, mobile) + ":" + type + ":";
        Object count = redisTemplate.opsForValue().get(key);
        if (count == null) {
            redisTemplate.opsForValue().set(key, "1", expire, TimeUnit.SECONDS);
        } else {
            int num = Integer.parseInt(String.valueOf(count)) + 1;
            redisTemplate.opsForValue().set(key, String.valueOf(num), expire, TimeUnit.SECONDS);
        }
    }

    public void delSmsCode(String nation, String mobile, String type) {
        String key = SMS_CODE_KEY + mobileKey(nation, mobile) + ":" + type + ":";
        redisTemplate.delete(key);
    }

    public void delSmsCodeErrorCount(String nation, String mobile, String type) {
        String key = SMS_CODE_ERROR_COUNT_KEY + mobileKey(nation, mobile) + ":" + type + ":";
        redisTemplate.delete(key);
    }

    private String mobileKey(String nation, String mobile) {
        return MobileUtils.fullMobile(nation, mobile);
    }


    public boolean checkEmailInterval(String email) {
        String key = EMAIL_INTERVAL_KEY + email;
        Object result = redisTemplate.opsForValue().get(key);
        return result == null;
    }

    public boolean checkEmailCodeErrorCount(String email, String type) {
        String key = EMAIL_CODE_ERROR_COUNT_KEY + email + ":" + type + ":";
        Object count = redisTemplate.opsForValue().get(key);
        if (count == null) return true;
        else {
            int num = Integer.parseInt(String.valueOf(count));
            return num < CODE_ERROR_MAX;
        }
    }

    public void createEmailCode(String email, String type, String code) {
        String key = EMAIL_CODE_KEY + email + ":" + type + ":";
        redisTemplate.opsForValue().set(key, code, EMAIL_ALIVE, TimeUnit.SECONDS);
    }

    public void sendEmailInterval(String email) {
        String key = EMAIL_INTERVAL_KEY + email;
        redisTemplate.opsForValue().set(key, "1", EMAIL_INTERVAL, TimeUnit.SECONDS);
    }

    public void delEmailInterval(String email) {
        String key = EMAIL_INTERVAL_KEY + email;
        redisTemplate.delete(key);
    }

    public String getEmailCode(String email, String type) {
        String key = EMAIL_CODE_KEY + email + ":" + type + ":";
        Object code = redisTemplate.opsForValue().get(key);
        if (code == null) return null;
        else return String.valueOf(code);
    }

    public void incrEmailCodeErrorCount(String email, String type) {
        String key0 = EMAIL_CODE_KEY + email + ":" + type + ":";
        Long expire = redisTemplate.getExpire(key0);
        if (expire == null || expire < 0) return;

        String key = EMAIL_CODE_ERROR_COUNT_KEY + email + ":" + type + ":";
        Object count = redisTemplate.opsForValue().get(key);
        if (count == null) {
            redisTemplate.opsForValue().set(key, "1", expire, TimeUnit.SECONDS);
        } else {
            int num = Integer.parseInt(String.valueOf(count)) + 1;
            redisTemplate.opsForValue().set(key, String.valueOf(num), expire, TimeUnit.SECONDS);
        }
    }

    public void delEmailCode(String email, String type) {
        String key = EMAIL_CODE_KEY + email + ":" + type + ":";
        redisTemplate.delete(key);
    }

    public void delEmailCodeErrorCount(String email, String type) {
        String key = EMAIL_CODE_ERROR_COUNT_KEY + email + ":" + type + ":";
        redisTemplate.delete(key);
    }

    public void createEmailCredential(String email, String credential, String type) {
        String key = EMAIL_CREDENTIAL_KEY + email + ":" + type + ":";
        redisTemplate.opsForValue().set(key, credential, EMAIL_ALIVE, TimeUnit.SECONDS);
    }

    public String getEmailCredential(String email, String type) {
        String key = EMAIL_CREDENTIAL_KEY + email + ":" + type + ":";
        Object credential = redisTemplate.opsForValue().get(key);
        if (credential == null) return null;
        else return String.valueOf(credential);
    }

    public void delEmailCredential(String email, String type) {
        String key = EMAIL_CREDENTIAL_KEY + email + ":" + type + ":";
        redisTemplate.delete(key);
    }

    public void createSmsCredential(String nation, String mobile, String credential, String type) {
        String key = SMS_CREDENTIAL_KEY + mobileKey(nation, mobile) + ":" + type + ":";
        redisTemplate.opsForValue().set(key, credential, SMS_ALIVE, TimeUnit.SECONDS);
    }

    public String getSmsCredential(String nation, String mobile, String type) {
        String key = SMS_CREDENTIAL_KEY + mobileKey(nation, mobile) + ":" + type + ":";
        Object credential = redisTemplate.opsForValue().get(key);
        if (credential == null) return null;
        else return String.valueOf(credential);
    }

    public void delSmsCredential(String nation, String mobile, String type) {
        String key = SMS_CREDENTIAL_KEY + mobileKey(nation, mobile) + ":" + type + ":";
        redisTemplate.delete(key);
    }

    public int getWalletPasswdErrorCount(String nation, String mobile) {
        String key = WALLET_PASSWD_ERROR_COUNT_KEY + mobileKey(nation, mobile);
        Object count = redisTemplate.opsForValue().get(key);
        if (count == null) return 0;
        else {
            return Integer.parseInt(String.valueOf(count));
        }
    }

    public void incrWalletPasswdErrorCount(String nation, String mobile) {
        String key = WALLET_PASSWD_ERROR_COUNT_KEY + mobileKey(nation, mobile);
        LocalDateTime now = LocalDateTime.now();
        LocalDateTime endOfDay = LocalDateTimeUtil.endOfDay(now);
        Duration between = LocalDateTimeUtil.between(now, endOfDay);
        Object count = redisTemplate.opsForValue().get(key);
        if (count == null) {
            redisTemplate.opsForValue().set(key, "1", between.getSeconds(), TimeUnit.SECONDS);
        } else {
            int num = Integer.parseInt(String.valueOf(count)) + 1;
            redisTemplate.opsForValue().set(key, String.valueOf(num), between.getSeconds(), TimeUnit.SECONDS);
        }
    }

    public void delWalletPasswdErrorCount(String nation, String mobile) {
        String key = WALLET_PASSWD_ERROR_COUNT_KEY + mobileKey(nation, mobile);
        redisTemplate.delete(key);
    }

}